package c03数据类型和运算符;

/**
 * 我的总结：主调者调用带参方法时，传递进去的是值而不是引用！Java只有值传递！！！
 * 调用过程：为方法建立一个栈空间，把主调者传递的变量值copy一份到栈中；然后方法再操作栈中的copy变量；
 * 结束后，销毁方法栈，当然包括里面的copy变量，整个过程中对它们的修改不会影响主调者相应的变量！
 * 那为什么会出现下面那些结果呢？下面来分析一下：
 *
 * @author 炜sama
 * @@1这个很明显，基本类型变量值就是变量内容，所以修改方法栈中的copy变量对它们没影响。
 * @@2对象变量可以储存在栈区或堆区，但是对象实体一定储存在堆内存！而变量则指向该堆内存， 方法里的变量名copy同样指向了该堆内存，因此通过这个copy也可以修改那个堆内存的内容！
 * @@2.2这里修改了copy变量的引用，也就是指向了新的堆内存，与原来指向的堆内存已经完全没有关系了！ 但是，假如Java像C++那样支持引用传递，结果就完全不一样了：会跟C++一样，主调者的t被改变，
 * t.i变成了100！但是结果不是这样，证明了Java只有值传递！
 * @@3很多人都以为这样无法改变字符串的内容是因为字符串不是引用类型——String当然是引用类型！ 其实与@@2.2相似，方法内已经改变了copy变量的引用，与主调者的引用不同了！而且String是一个
 * 不可变类，在方法里也不能修改String的内容，所以即使不改变他的引用也不怕它会修改原来的字符串内容了！
 */
public class Java值传递证明 {

	private static String ss = "xxx";

	public static void main(String[] args) {
		int i = 10;
		Test t = new Test(1);
		t.changeLocalVar(i);//试图利用该方法改变上面的i~
		System.err.println(i);//失败！i还是10！
		System.err.println(t.i);
		t.changeTestI(t);//试图利用该方法改变引用变量t的内容~
		System.err.println(t.i);//成功！t.i变成2！
		t.changeTest(t);//试图利用该方法改变整个t~
		System.err.println(t.i);//失败！t不变~

		String s = new String("我去年买了个表");
		t.changeLocalS(s);//试图利用该方法改变字符串内容~
		System.err.println(s);//还是不变！
		t.changeLocalS2(s);//试图利用该方法改变字符串内容~
		System.err.println(s);//还是不变！
	}

}

//测试用外部类
class Test {
	public int i;

	public Test(int i) {
		this.i = i;
	}

	//@@1：测试基本类型形参传递
	public void changeLocalVar(int i) {
		i = 99;
	}

	//@@2：测试引用类型形参传递
	public void changeTestI(Test t) {
		t.i = 2;//t不是main中的t！但是指向与main中t相同的堆空间，因此把那个空间里的i改变了！
	}

	//@@2.2：测试在方法内部修改引用类型形参的引用的结果
	public void changeTest(Test t) {
		t = new Test(100);//这个改变不能保留！！！
	}

	//@@3：测试字符串形参
	public void changeLocalS(String s) {
		s = "2333333333333";
	}

	//@@4：测试字符串形参
	public void changeLocalS2(String s) {
		//因为string是不可变类，所以这个方法的原理是，new一个s替换掉相应字符后的字符串，然后把堆内存赋值给s。
		s.replace("表", "包");
	}
}